// LemCoop
// Copyright (C) 2013  Oliver Naumann <bldrax@gmail.com>

// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

#ifndef LEMC_LOBBYSTATE_H
#define LEMC_LOBBYSTATE_H

#include <WindowsIncludes.h>
#include <allegro5/allegro.h>
#include <allegro5/allegro_font.h>
#include <allegro5/allegro_ttf.h>
#include <string>
#include <cstdint>
#include <map>
#include <MessageIdentifiers.h>
#include <StringCompressor.h>
#include <rapidxml.hpp>
#include <rapidxml_utils.hpp>
#include <boost/lexical_cast.hpp>

#include "gamestate.h"
#include "../util/helpers.h"
#include "../network/clientconnectionlist.h"
#include "../network/clientconnection.h"
#include "../network/raknetserver.h"
#include "../network/raknetclient.h"
#include "../network/workmanager.h"
#include "../network/job.h"
#include "../gui/dialog.h"
#include "../gui/button.h"
#include "../gui/valuelist.h"
#include "../gui/textfield.h"
#include "../gui/textbox.h"
#include "../gui/checkbox.h"
#include "../gui/helpsymbol.h"

struct LevelInfo
{
	std::int32_t id;
	std::int32_t number;
	std::int32_t player_number;
	std::string name;
	std::string filename;
};

class LobbyState : public GameState
{
private:
	bool m_is_server;
	RakNetServer* m_server;
	RakNetClient* m_client;
	std::string m_guid;
	std::string m_client_name;
	WorkManager* m_work_manager;

	bool m_game_started;
	bool m_shutdown_network_on_state_end;

	bool m_level_chosen;

	// This is set by the server only. For the client, it is the player number of the last known chosen level.
	int m_number_of_players_set;

	// True if the helpsymbols have to be recreated (e.g. because some client information has changed).
	bool m_rebuild_color_helpsymbols;

	// The number of checkboxes that are shown to choose colors. This controls whether a new checkbox must be created
	// (the player number has been increased) or an old checkbox must be destroyed (player number has decreased).
	int m_color_checkboxes_shown;
	LevelInfo m_current_level;
	ALLEGRO_TIMER* m_send_level_info_timer;

	ClientConnectionList m_client_list;
	ALLEGRO_FONT* m_client_list_font;

	Dialog* m_dialog;
	std::map<std::string, LevelInfo> m_levels;

	void ServerInit();
	void ClientInit();
	void ServerCleanup();
	void ClientCleanup();

	void SendMyClientInformation();
	void ChangeControlInfo();

	void DoServerWork();
	void DoClientWork();

	void ServerProcessIncomingConnection(Job incoming_connection_job);
	void ServerRemovePlayer(std::string guid);
	void ServerKickPlayer(std::string guid);
	void ServerProcessClientInformation(Job connection_information_job);
	void ServerProcessChatMessage(Job chat_message_job);
	void ServerEnterChatMessage(std::string message);
	void ServerSendChatMessage(std::string message, const unsigned char color[3]);
	void ServerLoadLevelList();
	void ServerStartGame();

	void ClientWaitForConnection();
	void ClientProcessClosedConnection();
	void ClientProcessRemoveClient(Job remove_client_job);
	void ClientProcessClientInformation(Job connection_information_job);
	void ClientProcessChatMessage(Job chat_message_job);
	void ClientEnterChatMessage(std::string message);
	void ClientSendChatMessage(std::string message, const unsigned char color[3]);
	void ClientProcessLevelInfo(Job levelinfo_job);
	void ClientProcessStartGame();

	void ServerUpdate();
	void ClientUpdate();

public:
	LobbyState(GameEngine* engine);
	~LobbyState();

	void Init(bool is_server, std::string client_name);
	void HandleInput(ALLEGRO_EVENT next_event);
	void Update(float timing_factor);
	void Draw();
};

#endif